package cn.imatu.framework.data.mate.fieldconvert;

import cn.imatu.framework.data.mate.fieldbind.inter.IFieldBindAnnotationDataGetter;
import cn.imatu.framework.data.mate.fieldconvert.inter.IFieldValueConvert;
import cn.imatu.framework.data.mate.fieldconvert.model.FieldDefine;
import cn.imatu.framework.tool.core.reflection.MetaObject;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 字段值管理器
 *
 * @author shenguangyang
 */
@Slf4j
@Component
public class SetTargetFieldValueManager {
    @Resource
    private Map<String, ConvertFieldTypeHandler<?>> baseFieldValueHandlerBean;

    /**
     * key: 目标字段类型, eg: java.util.List<java.lang.String>, java.lang.String
     */
    private final Map<String, ConvertFieldTypeHandler<?>> baseFieldValueHandlerMap = new HashMap<>();

    @PostConstruct
    public void init() {
        baseFieldValueHandlerBean.forEach((k, v) -> {
            Type type = getType(v);
            baseFieldValueHandlerMap.put(type.getTypeName(), v);
        });
    }

    private Type getType(Object obj) {
        Type[] types = obj.getClass().getGenericInterfaces();
        ParameterizedType parameterizedType = (ParameterizedType) types[0];
        return parameterizedType.getActualTypeArguments()[0];
    }


    /**
     * 设置元数据对象<br>
     * 每个对象的属性都会调用一次, 比如需要处理一个对象, 其中有10个字段需要进行字段绑定操作, 那么就会被调用10次
     *
     * @param metaObject     处理的对象元数据
     * @param fieldDefine 字段定义数据, 可以获取当前处理的字段上自定义的字段绑定注解数据, 来自
     *                       {@link IFieldBindAnnotationDataGetter#initFieldBindAnnotation(Annotation)} (Annotation)} ()}
     *                       方法的返回值
     */
    public void setTargetValue(MetaObject metaObject, Object obj, IFieldValueConvert fieldValueConvert,
                               FieldDefine fieldDefine, boolean isReturn) throws Exception {

        // 请求
        if (!isReturn) {

            FieldHandlerInfo fieldHandlerInfo = getFieldHandlerInfo(fieldDefine, fieldDefine.getField(), obj);
            if (!fieldHandlerInfo.isExe()) {
                return;
            }
            Object value = fieldHandlerInfo.getFieldValue();

            List<String> sourceFieldValues = fieldHandlerInfo.getSourceFieldValueHandler().getValue(value, fieldDefine);
            if (!fieldValueConvert.isConvertToTarget(sourceFieldValues, fieldDefine.getAnnot())) {
                return;
            }
            List<String> targetValues = fieldValueConvert.toTarget(fieldDefine, sourceFieldValues);
            fieldHandlerInfo.getTargetFieldValueHandler().setValue(targetValues, metaObject, fieldDefine.getTargetField(), fieldDefine.getAnnot());
            return;
        }


        FieldHandlerInfo fieldHandlerInfo = getFieldHandlerInfo(fieldDefine, fieldDefine.getTargetField(), obj);
        if (!fieldHandlerInfo.isExe()) {
            return;
        }
        Object value = fieldHandlerInfo.getFieldValue();
        List<String> sourceFieldValues = fieldHandlerInfo.getTargetFieldValueHandler().getValue(value, fieldDefine);

        if (!fieldValueConvert.isConvertToSource(sourceFieldValues, fieldDefine.getAnnot())) {
            return;
        }

        List<String> targetValues = fieldValueConvert.toSource(fieldDefine, sourceFieldValues);
        fieldHandlerInfo.getSourceFieldValueHandler().setValue(targetValues, metaObject, fieldDefine.getField(), fieldDefine.getAnnot());
    }

    @Data
    public static class FieldHandlerInfo {
        ConvertFieldTypeHandler<?> targetFieldValueHandler;
        ConvertFieldTypeHandler<?> sourceFieldValueHandler;
        Object fieldValue;

        public boolean isExe() {
            return targetFieldValueHandler != null && sourceFieldValueHandler != null && fieldValue != null;
        }
    }

    private FieldHandlerInfo getFieldHandlerInfo(FieldDefine fieldDefine, Field field, Object obj) throws Exception {
        FieldHandlerInfo result = new FieldHandlerInfo();
        Object value = field.get(obj);
        if (value == null) {
            return result;
        }

        // 如果是返回, 将key转成url赋值到注解所在字段
        String typeName = fieldDefine.getTargetField().getGenericType().getTypeName();
        ConvertFieldTypeHandler<?> targetFieldValueHandler = baseFieldValueHandlerMap.get(typeName);
        if (Objects.isNull(targetFieldValueHandler)) {
            log.warn("忽略目标字段转换 ===> 字段 [{}] 类型为 [{}] 暂时不支持", fieldDefine.getTargetField().getName(), typeName);
            return result;
        }

        typeName = fieldDefine.getField().getGenericType().getTypeName();
        ConvertFieldTypeHandler<?> sourceFieldValueHandler = baseFieldValueHandlerMap.get(typeName);
        if (Objects.isNull(sourceFieldValueHandler)) {
            log.warn("忽略原字段转换字 ===> 字段 [{}] 类型为 [{}] 暂时不支持", fieldDefine.getField().getName(), typeName);
            return result;
        }

        result.setFieldValue(value);
        result.setTargetFieldValueHandler(targetFieldValueHandler);
        result.setSourceFieldValueHandler(sourceFieldValueHandler);
        return result;
    }

}
